package com.xyzh05.webapp.action;

import com.opensymphony.xwork2.Preparable;
import org.apache.struts2.ServletActionContext;
import com.xyzh05.Constants;
import com.xyzh05.model.Role;
import com.xyzh05.model.User;
import com.xyzh05.service.UserExistsException;
import com.xyzh05.util.PageUtil;
import com.xyzh05.webapp.util.RequestUtil;
import org.springframework.mail.MailException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;

/**
 * Action for facilitating User Management feature.
 */
public class UserAction extends BaseAction implements Preparable {
    private static final long serialVersionUID = 6776558938712115191L;

    private PasswordEncoder passwordEncoder;
    private List<User> users;
    private User user;
    private String id;
    private String query;
	private String locatioin;
	private String address;
	private String province;
	private String city;
	private String county;
	private Integer resultCode;
	private String password;
	private String newPassword;
	private String confirmPassword;
    private Integer currentPage;
    private Integer pageSize;

    /**
     * Grab the entity from the database before populating with request parameters
     */
    public void prepare()throws Exception {
    }

    /**
     * Holder for users to display on list screen
     *
     * @return list of users
     */
    public List<User> getUsers() {
        return users;
    }

    public Integer getResultCode() {
		return resultCode;
	}

	public void setResultCode(Integer resultCode) {
		this.resultCode = resultCode;
	}

	public PasswordEncoder getPasswordEncoder() {
		return passwordEncoder;
	}

	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

	public void setId(String id) {
        this.id = id;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public void setQ(String q) {
        this.query = q;
    }

    public String getQuery() {
		return query;
	}

	public void setQuery(String query) {
		this.query = query;
	}

	public String getLocatioin() {
		return locatioin;
	}

	public void setLocatioin(String locatioin) {
		this.locatioin = locatioin;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getProvince() {
		return province;
	}

	public void setProvince(String province) {
		this.province = province;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getCounty() {
		return county;
	}

	public void setCounty(String county) {
		this.county = county;
	}

	public String getId() {
		return id;
	}

	public void setUsers(List<User> users) {
		this.users = users;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getNewPassword() {
		return newPassword;
	}

	public void setNewPassword(String newPassword) {
		this.newPassword = newPassword;
	}

	public String getConfirmPassword() {
		return confirmPassword;
	}

	public void setConfirmPassword(String confirmPassword) {
		this.confirmPassword = confirmPassword;
	}

	public Integer getCurrentPage() {
		return currentPage;
	}

	public void setCurrentPage(Integer currentPage) {
		this.currentPage = currentPage;
	}

	public Integer getPageSize() {
		return pageSize;
	}

	public void setPageSize(Integer pageSize) {
		this.pageSize = pageSize;
	}

	
	/**
     * Delete the user passed in.
     *
     * @return success
     */
    public String delete() {
        userManager.removeUser(user.getId().toString());
        List<Object> args = new ArrayList<Object>();
        args.add(user.getDisplayName());
        saveMessage(getText("user.deleted", args));

        return SUCCESS;
    }

    /**
     * Grab the user from the database based on the "id" passed in.
     *
     * @return success if user found
     * @throws IOException can happen when sending a "forbidden" from response.sendError()
     */
    public String edit() throws IOException {
        HttpServletRequest request = getRequest();
        boolean editProfile = (request.getRequestURI().indexOf("editProfile") > -1);

        // if URL is "editProfile" - make sure it's the current user
        if (editProfile && ((request.getParameter("id") != null) || (request.getParameter("from") != null))) {
            ServletActionContext.getResponse().sendError(HttpServletResponse.SC_FORBIDDEN);
            log.warn("User '" + request.getRemoteUser() + "' is trying to edit user '" +
                    request.getParameter("id") + "'");
            return null;
        }

        // if a user's id is passed in
        if (id != null) {
            // lookup the user using that id
            user = userManager.getUser(id);
        } else if (editProfile) {
            user = userManager.getUserByUsername(request.getRemoteUser());
        } else {
            user = new User();
            user.addRole(new Role(Constants.USER_ROLE));
        }

        if (user.getUsername() != null) {
            user.setConfirmPassword(user.getPassword());

            // if user logged in with remember me, display a warning that they can't change passwords
            log.debug("checking for remember me login...");

            AuthenticationTrustResolver resolver = new AuthenticationTrustResolverImpl();
            SecurityContext ctx = SecurityContextHolder.getContext();

            if (ctx != null) {
                Authentication auth = ctx.getAuthentication();

                if (resolver.isRememberMe(auth)) {
                    getSession().setAttribute("cookieLogin", "true");
                    saveMessage(getText("userProfile.cookieLogin"));
                }
            }
        }

        return SUCCESS;
    }

    /**
     * Default: just returns "success"
     *
     * @return "success"
     */
    public String execute() {
        return SUCCESS;
    }

    /**
     * Sends users to "mainMenu" when !from.equals("list"). Sends everyone else to "cancel"
     *
     * @return "mainMenu" or "cancel"
     */
    public String cancel() {
        if (!"list".equals(from)) {
            return "mainMenu";
        }
        return "cancel";
    }

    /**
     * Save user
     *
     * @return success if everything worked, otherwise input
     * @throws Exception when setting "access denied" fails on response
     */
    public String save() throws Exception {
        
    	Integer originalVersion = user.getVersion().intValue();

        boolean isNew = ("".equals(getRequest().getParameter("user.version")));
        // only attempt to change roles if user is admin
        // for other users, prepare() method will handle populating
        if (getRequest().isUserInRole(Constants.ADMIN_ROLE)) {
            user.getRoles().clear(); // APF-788: Removing roles from user doesn't work
            String[] userRoles = getRequest().getParameterValues("userRoles");

            for (int i = 0; userRoles != null && i < userRoles.length; i++) {
                String roleName = userRoles[i];
                user.addRole(roleManager.getRole(roleName));
            }
        }

        try {
            userManager.saveUser(user);
        } catch (AccessDeniedException ade) {
            // thrown by UserSecurityAdvice configured in aop:advisor userManagerSecurity
            log.warn(ade.getMessage());
            getResponse().sendError(HttpServletResponse.SC_FORBIDDEN);
            return null;
        } catch (UserExistsException e) {
            List<Object> args = new ArrayList<Object>();
            args.add(user.getUsername());
            args.add(user.getEmail());
            addActionError(getText("errors.existing.user", args));

            // reset the version # to what was passed in
            user.setVersion(originalVersion.longValue());
            // redisplay the unencrypted passwords
            user.setPassword(user.getConfirmPassword());
            return INPUT;
        }

        if (!"list".equals(from)) {
            // add success messages
            saveMessage(getText("user.saved"));
            return "mainMenu";
        } else {
            // add success messages
            List<Object> args = new ArrayList<Object>();
            args.add(user.getDisplayName());
            if (isNew) {
                saveMessage(getText("user.added", args));
                // Send an account information e-mail
                mailMessage.setSubject(getText("signup.email.subject"));
                try {
                    sendUserMessage(user, getText("newuser.email.message", args), RequestUtil.getAppURL(getRequest()));
                } catch (MailException me) {
                    addActionError(me.getCause().getLocalizedMessage());
                }
                return SUCCESS;
            } else {
                saveMessage(getText("user.updated.byAdmin", args));
                return INPUT;
            }
        }
    }

    /**
     * Fetch all users from database and put into local "users" variable for retrieval in the UI.
     *
     * @return "success" if no exceptions thrown
     */
    public String list() {
        users = userManager.searchAuditUsers(Short.valueOf("1"), currentPage==null&&pageSize==null?0:PageUtil.getStartNum(currentPage, pageSize), pageSize==null?10:pageSize);
        return SUCCESS;
    }

    public String saveUserPass(){
    	if(id != null){
    		user = userManager.getUser(id);
    		if(!user.getPassword().equals(passwordEncoder.encodePassword(password, null))){
    			resultCode = 2;
    		}else{
    			user.setPassword(passwordEncoder.encodePassword(confirmPassword, null));
    			try {
    				userManager.saveOrUpdate(user);
    	    		resultCode = 1;
				} catch (Exception e) {
		    		resultCode = 3;
				}
    		}
    	}else{
    		resultCode = 3;
    	}
    	return SUCCESS;
    }
    
    
    /**
     * 从Cookie取出已经设置的位置
     */
    public String setLocation(){
    	Cookie cookieLocation = RequestUtil.getCookie(getRequest(), "cookieLocation");
    	if(cookieLocation != null){
    		locatioin = cookieLocation.getValue();
    		if(locatioin != null){
    			try {
    				locatioin = URLDecoder.decode(locatioin, "utf-8");
    			} catch (UnsupportedEncodingException e) {
    				e.printStackTrace();
    			}    			
    		}
    	}
    	Cookie cookieAddress = RequestUtil.getCookie(getRequest(), "cookieAddress");
    	if(cookieAddress != null){
    		address = cookieAddress.getValue();
    		if(address != null){
    			try {
    				address = URLDecoder.decode(address, "utf-8");
    			} catch (UnsupportedEncodingException e) {
    				e.printStackTrace();
    			}    			
    		}
    	}
    	Cookie cookieProvince = RequestUtil.getCookie(getRequest(), "cookieProvince");
    	if(cookieProvince != null){
    		province = cookieProvince.getValue();
    		if(province != null){
    			try {
    				province = URLDecoder.decode(province, "utf-8");
    			} catch (UnsupportedEncodingException e) {
    				e.printStackTrace();
    			}    			
    		}
    	}
    	Cookie cookieCity = RequestUtil.getCookie(getRequest(), "cookieCity");
    	if(cookieCity != null){
    		city = cookieCity.getValue();
    		if(city != null){
    			try {
    				city = URLDecoder.decode(city, "utf-8");
    			} catch (UnsupportedEncodingException e) {
    				e.printStackTrace();
    			}    			
    		}
    	}
    	Cookie cookieCounty = RequestUtil.getCookie(getRequest(), "cookieCounty");
    	if(cookieCounty != null){
    		county = cookieCounty.getValue();
    		if(county != null){
    			try {
    				county = URLDecoder.decode(county, "utf-8");
    			} catch (UnsupportedEncodingException e) {
    				e.printStackTrace();
    			}    			
    		}
    	}
    	return SUCCESS;
    }
}
